package consul

import (
	"fmt"
	"github.com/hashicorp/consul/api"
	"go.uber.org/zap"
	"hosptial-record/global"
	"os"
	"os/signal"
	"syscall"
)

type RegistryClient interface {
	Register(config RegisterServerConfig) error
	DeRegister(id string) error
	GetAgent() (*api.Client, error)
}

func NewRegistryClient(host string, port int) RegistryClient {
	return &Registry{
		Host: host,
		Port: port,
	}
}

type RegisterConfig struct {
	Host string
	Port int
}

type RegisterServerConfig struct {
	Host string
	Port int
	Name string
	Tags []string
	ID   string
}

type Registry struct {
	Host string
	Port int
}

// GetAgent 获取客户端实例
func (r Registry) GetAgent() (*api.Client, error) {
	cfg := api.DefaultConfig()
	cfg.Address = fmt.Sprintf("%s:%d", r.Host, r.Port)
	client, err := api.NewClient(cfg)
	if err != nil {
		zap.S().Error("服务注册失败:", err.Error())
	}
	return client, err
}

func (r Registry) Register(config RegisterServerConfig) error {
	client, err := r.GetAgent()
	if err != nil {
		zap.S().Error("服务注册失败:", err.Error())
		panic(err)
	}
	// 配置健康检查
	check := api.AgentServiceCheck{
		HTTP:                           fmt.Sprintf("http://%s:%d/health", config.Host, config.Port),
		Timeout:                        "5s",
		Interval:                       "5s",
		DeregisterCriticalServiceAfter: "10s",
	}
	// 注册服务
	registration := &api.AgentServiceRegistration{
		Name: global.ServerConfig.Name,
		// 随机生成ID
		ID:      config.ID,
		Address: config.Host,
		Tags:    config.Tags,
		Port:    config.Port,
		Check:   &check,
	}
	if err := client.Agent().ServiceRegister(registration); err != nil {
		return err
	}
	return nil
}

func (r Registry) DeRegister(id string) error {
	client, err := r.GetAgent()
	if err != nil {
		zap.S().Error("服务注册失败:", err.Error())
		return err
	}
	quit := make(chan os.Signal)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
	<-quit
	// 进行consul的退出逻辑
	if err := client.Agent().ServiceDeregister(id); err != nil {
		// 退出失败
		zap.S().Errorf("退出consul失败：%s", err.Error())
		panic(err)
	}
	zap.S().Info("退出成功")
	os.Exit(0)
	return nil
}
